package com.repair.worker.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.repair.api.worker.constant.WorkerOperateType;
import com.repair.api.worker.constant.WorkerStateEnum;
import com.repair.api.worker.request.WorkerAuthRealNameRequest;
import com.repair.api.worker.request.WorkerBlockRequest;
import com.repair.api.worker.request.WorkerQueryPageRequest;
import com.repair.api.worker.request.WorkerRegisterRequest;
import com.repair.api.worker.request.condition.WorkerBlockCondition;
import com.repair.api.worker.request.param.WorkerBlockParam;
import com.repair.api.worker.request.param.WorkerQueryParam;
import com.repair.api.worker.request.param.WorkerRealNameAuthParam;
import com.repair.api.worker.response.WorkerOperateResponse;
import com.repair.api.worker.response.WorkerQueryResponse;
import com.repair.api.worker.response.data.WorkerInfo;
import com.repair.base.exception.BizErrorCode;
import com.repair.base.exception.SystemErrorCode;
import com.repair.base.exception.SystemException;
import com.repair.base.response.PageResponse;
import com.repair.base.utils.ResponseCode;
import com.repair.satoken.utils.StpKit;
import com.repair.worker.exception.WorkerServiceErrorCode;
import com.repair.worker.exception.WorkerServiceException;
import com.repair.worker.mapper.WorkerMapper;
import com.repair.worker.pojo.convertor.WorkerConvertor;
import com.repair.worker.pojo.dto.WorkerUpdateParam;
import com.repair.worker.pojo.entity.Worker;
import com.repair.worker.service.WorkerOperateStreamService;
import com.repair.worker.service.WorkerService;
import com.repair.worker.util.NicknameGenerator;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.List;
import java.util.stream.Collectors;

import static com.repair.api.user.constant.NicknamePrefix.NICKNAME_Worker_PREFIX;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author 张强
 * @since 2024-09-13
 */
@Service
public class WorkerServiceImpl extends ServiceImpl<WorkerMapper, Worker> implements WorkerService, InitializingBean {
    @Autowired
    private WorkerMapper workerMapper;
    @Autowired
    private SqlSessionFactory sqlSessionFactory;

    private RBloomFilter<String> nickNameBloomFilter;
    @Autowired
    private WorkerOperateStreamService workerOperateStreamService;

    @Autowired
    private RedissonClient redissonClient;

    @Override
    public Worker selectByPhone(String phone) {
        return workerMapper.selectOne(new QueryWrapper<Worker>().eq("phone", phone));
    }

    @Override
    public WorkerOperateResponse register(WorkerRegisterRequest workerRegisterRequest) {
        //获取手机号
        Worker worker = new Worker();
        String phone = workerRegisterRequest.getPhone();
        worker.setPhone(phone);
        //生成昵称
        StringBuilder nickPrefix = new StringBuilder(NICKNAME_Worker_PREFIX);
        String nickname = NicknameGenerator.generateNickname(nickPrefix);
        worker.setNickname(nickname);
        //初始化状态
        worker.setWorkerStatus(WorkerStateEnum.INIT.name());
        //初始化实名状态
        worker.setAuthenticationStatus(0);
        //初始化师傅等级
        worker.setWorkerLevel("一级");
        //初始化钱包金额
        worker.setTotalAmount(new BigDecimal("0.00"));
        //初始化接单总数
        worker.setReceivedOrderSum(0);
        //初始化公司id
        worker.setCompanyId(0L);
        //插入数据
        int i = baseMapper.insert(worker);
        if (i == 0) {
            throw new SystemException(SystemErrorCode.INSERT_FAILED);
        }
        //插入操作流水
        long l = workerOperateStreamService.insertStream(worker, WorkerOperateType.REGISTER);
        if (l == 0) {
            throw new SystemException(SystemErrorCode.INSERT_FAILED);
        }
        //设置状态是否成功
        WorkerOperateResponse response = new WorkerOperateResponse();
        response.setSuccess(true);
        return response;
    }

    @Override
    public PageResponse<WorkerInfo> getAllWorkers(WorkerQueryPageRequest<WorkerQueryParam> queryParam) {
        // 获取查询参数中的页面大小
        int pageSize = queryParam.getPageSize();
        // 确保当前页码至少为1
        int currentPage = Math.max(queryParam.getCurrentPage(), 1);
        // 计算查询时的偏移量
        int offset = (currentPage - 1) * pageSize;
        // 使用try-with-resources确保SqlSession资源被正确关闭
        try (SqlSession session = sqlSessionFactory.openSession()) {
            // 获取WorkerMapper实例
            WorkerMapper workerMapper = session.getMapper(WorkerMapper.class);

            // 查询工人列表
            List<Worker> workerList = workerMapper.selectWorkers(
                    queryParam.getData().getNickName(),
                    queryParam.getData().getPhone(),
                    queryParam.getData().getWorkerLevel(),
                    queryParam.getData().getWorkerStatus(),
                    queryParam.getData().getAuthenticationStatus(),
                    queryParam.getData().getCreateTimeMin(),
                    queryParam.getData().getCreateTimeMax(),
                    queryParam.getData().getTotalOrderAmountMin(),
                    queryParam.getData().getTotalOrderAmountMax(),
                    queryParam.getData().getReceivedOrderSumMin(),
                    queryParam.getData().getReceivedOrderSumMax(),
                    queryParam.getData().getId(),
                    offset,
                    pageSize
            );

            // 计算总记录数
            int total = workerMapper.countWorkers(
                    queryParam.getData().getNickName(),
                    queryParam.getData().getPhone(),
                    queryParam.getData().getWorkerLevel(),
                    queryParam.getData().getWorkerStatus(),
                    queryParam.getData().getAuthenticationStatus(),
                    queryParam.getData().getCreateTimeMin(),
                    queryParam.getData().getCreateTimeMax(),
                    queryParam.getData().getTotalOrderAmountMin(),
                    queryParam.getData().getTotalOrderAmountMax(),
                    queryParam.getData().getReceivedOrderSumMin(),
                    queryParam.getData().getReceivedOrderSumMax(),
                    queryParam.getData().getId()
            );

            // 初始化分页响应对象
            PageResponse<WorkerInfo> pageResponse = new PageResponse<>();
            // 设置响应成功
            pageResponse.setSuccess(true);
            // 将查询结果转换为WorkerInfo列表
            pageResponse.setData(workerList.stream()
                    .map(worker -> {
                        WorkerInfo workerInfo = new WorkerInfo();
                        BeanUtils.copyProperties(worker, workerInfo);
                        return workerInfo;
                    })
                    .collect(Collectors.toList()));
            // 设置当前页码
            pageResponse.setCurrentPage(currentPage);
            // 设置总记录数
            pageResponse.setTotal(total);
            // 计算总页数
            pageResponse.setPageTotal((total + pageSize - 1) / pageSize);
            // 设置页面大小
            pageResponse.setPageSize(pageSize);
            // 返回分页响应对象
            return pageResponse;
        } catch (Exception e) {
            // 异常处理，设置响应失败
            PageResponse<WorkerInfo> pageResponse = new PageResponse<>();
            pageResponse.setSuccess(false);
            e.printStackTrace();
            return pageResponse;
        }
    }

    @Override
    public Worker getWorkerById(Long id) {
        return workerMapper.selectById(id);
    }


    @Override
    public WorkerInfo selectWorkerInfo(Long workerId) {
        Worker worker = workerMapper.selectById(workerId);
        if (worker == null) {
            throw new SystemException(SystemErrorCode.SELECT_FAILED);
        }
        WorkerInfo workerInfo = new WorkerInfo();
        BeanUtils.copyProperties(worker, workerInfo);
        return workerInfo;
    }

    @Override
    public void updateWorkerAuth(WorkerAuthRealNameRequest<WorkerRealNameAuthParam> request) {
        WorkerRealNameAuthParam param = request.getData();
        if (param == null ||
                param.getIdCardNumber() == null ||
                param.getRealName() == null) {
            throw new SystemException(BizErrorCode.REAL_NAME_AUTH_IS_NULL);
        }
        UpdateWrapper<Worker> wrapper = new UpdateWrapper<>();
        wrapper.eq("id", param.getWorkerId())
                .eq("authentication_status", 0)
                .set("authentication_status", 1)
                .set("real_name", param.getRealName())
                .set("id_card_number", param.getIdCardNumber());
        baseMapper.update(wrapper);
        refreshSession(param.getWorkerId());
    }

    private void refreshSession(Long workerId) {
        Worker worker = baseMapper.selectOne(new QueryWrapper<Worker>().eq("id", workerId));
        WorkerInfo workerInfo = new WorkerInfo();
        BeanUtils.copyProperties(worker, workerInfo);
        StpKit.WORKER.getSessionByLoginId(workerId).set(workerInfo.getId().toString(), workerInfo);
    }

    @Override
    public WorkerQueryResponse<Boolean> blockWorker(WorkerBlockRequest<WorkerBlockParam> param) {
        WorkerBlockCondition blockCondition = (WorkerBlockCondition)param.getWorkerCondition();
        Long id = blockCondition.getId();
//        String workerStatus = blockCondition.getWorkerStatus();
        UpdateWrapper<Worker> wrapper = new UpdateWrapper<>();
        wrapper.eq("id", id).set("worker_status", WorkerStateEnum.BLOCKED.name());
        int i = baseMapper.update(wrapper);
        if (i != 1) {
            throw new SystemException(ResponseCode.UPDATE_FAILED);
        }
        WorkerQueryResponse<Boolean> response = new WorkerQueryResponse<>();
        response.setSuccess(true);
        refreshSession(id);
        return response;
    }

    @Override
    public WorkerQueryResponse<Boolean> cancelBlockWorker(WorkerBlockRequest<WorkerBlockParam> param) {
        WorkerBlockCondition blockCondition = (WorkerBlockCondition)param.getWorkerCondition();
        Long id = blockCondition.getId();
//        String workerStatus = blockCondition.getWorkerStatus();
        UpdateWrapper<Worker> wrapper = new UpdateWrapper<>();
        wrapper.eq("id", id).set("worker_status", WorkerStateEnum.INIT.name());
        int i = baseMapper.update(wrapper);
        if (i != 1) {
            throw new SystemException(ResponseCode.UPDATE_FAILED);
        }
        WorkerQueryResponse<Boolean> response = new WorkerQueryResponse<>();
        response.setSuccess(true);
        refreshSession(id);
        return response;
    }
    public boolean nickNameExist(String nickname) {
        //如果布隆过滤器中存在，再进行数据库二次判断
        if (this.nickNameBloomFilter != null && this.nickNameBloomFilter.contains(nickname)) {
            return workerMapper.selectOne(new QueryWrapper<Worker>().eq("nickname", nickname)) != null;
        }
        return false;
    }
    private void addNickNameToBloomFilter(String nickname) {
        nickNameBloomFilter.add(nickname);
    }
    @Override
    public void updateWorkerNickName(WorkerUpdateParam workerUpdateParam) {
        Long workerId = Long.valueOf((String) StpKit.WORKER.getLoginId());
        Worker worker = new Worker();
        BeanUtils.copyProperties(workerUpdateParam, worker);
        worker.setId(workerId);
        Worker workerExists = workerMapper.selectById(worker.getId());
        if (workerExists == null) {
            throw new WorkerServiceException(WorkerServiceErrorCode.WORKER_NOT_EXISTS);
        }
        if (StringUtils.isEmpty(workerUpdateParam.getNickname()) || nickNameExist(workerUpdateParam.getNickname())) {
            throw new WorkerServiceException(WorkerServiceErrorCode.WORKER_NICKNAME_EXISTS);
        }
        int i = workerMapper.updateById(worker);
        if (i == 0) {
            throw new SystemException(SystemErrorCode.UPDATE_FAILED);
        }
        long l = workerOperateStreamService.insertStream(worker, WorkerOperateType.UPDATE_INFO);
        if (l == 0) {
            throw new SystemException(SystemErrorCode.INSERT_FAILED);
        }
        // 添加到布隆过滤器
        addNickNameToBloomFilter(workerUpdateParam.getNickname());
        // 刷新session
        refreshUserInSession(workerId);
    }

    @Override
    public void uploadWorkerProfile(WorkerUpdateParam workerUpdateParam) {
        Long workerId = Long.valueOf((String) StpKit.WORKER.getLoginId());
        Worker worker = new Worker();
        BeanUtils.copyProperties(workerUpdateParam, worker);
        worker.setId(workerId);
        int i = workerMapper.updateById(worker);
        if (i == 0){
            throw new SystemException(SystemErrorCode.UPDATE_FAILED);
        }
        long l = workerOperateStreamService.insertStream(worker, WorkerOperateType.UPDATE_INFO);
        if (l == 0) {
            throw new SystemException(SystemErrorCode.INSERT_FAILED);
        }
    }

    private void refreshUserInSession(Long workerId) {
        Worker worker = workerMapper.selectOne(new QueryWrapper<Worker>().eq("id", workerId));
        WorkerInfo workerInfo = WorkerConvertor.INSTANCE.mapToVo(worker);
        StpKit.USER.getSessionByLoginId(workerId).set(workerInfo.getId().toString(), workerInfo);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        this.nickNameBloomFilter = redissonClient.getBloomFilter("WorkerNickName");
        if (nickNameBloomFilter != null && !nickNameBloomFilter.isExists()) {
            this.nickNameBloomFilter.tryInit(100000L, 0.01);
        }
    }
}
